<?php
class APPWeixinPay{
	public $notify_url    = '';//异步处理地址
	public $return_url    = '';//同步处理地址
	public $show_url      = '';//商品展示地址
	public $appid         = '';//appid
	public $appkey        = '';//paysign key
	public $sign_type     = 'sha1';//签名方式
	public $partner_id    = '';//商户号
	public $partner_key   = '';//通加密串
	public $app_sercert   = '';//app sercert
	public $is_debug      = false;//true为调试模式，价格会设置成0.01，false为非调试模式，价格按正常来
	public $logs_path     = '';
	public $is_new_weixin = false;

	public function __construct() {
		//日志保存目录
		$this->logs_path = dirname(__FILE__).'/Logs/';
		$this->logs_path_file = $this->logs_path . 'app_debug_' . date('Y_m_d') . '.log';
		if(file_exists($this->logs_path)==false){
			mkdir($this->logs_path,true);
		}
		$this->config();
    }
	/**
	 * 配置
	 */
	public function config(){
		//appid
		$appid = C('weixin_pay_appid');
		$this->appid = $appid ? $appid : $this->appid;

		//paysign key
		$appkey = C('weixin_pay_appkey');
		$this->appkey = $appkey ? $appkey : $this->appkey;

		//method
		$sign_type = C('weixin_pay_sign_type');
		$this->sign_type = $sign_type ? $sign_type : $this->sign_type;

		//通加密串
		$partner_key = C('weixin_pay_partner_key');
		$this->partner_key = $partner_key ? $partner_key : $this->partner_key;

		//商户号
		$partner_id = C('weixin_pay_partner_id');
		$this->partner_id = $partner_id ? $partner_id : $this->partner_id;

		$app_sercert = C('weixin_pay_app_sercert');
		$this->app_sercert = $app_sercert ? $app_sercert : $this->app_sercert;

		$is_new_weixin = C('weixin_is_new_pay');
		$this->is_new_weixin = $is_new_weixin ? $is_new_weixin : $this->is_new_weixin;
	}
	public function get_pay_order_info($order_sn, $body, $total_fee, $notify_url){
		$this->config();
		//新版本微信支付
		if($this->is_new_weixin){
			return $this->get_pay_unifiedorder_info($order_sn, $body, $total_fee, $notify_url);
		}
		//获取app package
		$package_params["bank_type"]        = "WX";//银行通道类型;固定为"WX";
		$package_params["body"]             = $body;//商品描述
		$package_params["partner"]          = $this->partner_id;//商户号
		$package_params["out_trade_no"]     = $order_sn;//商户订单号
		$package_params["total_fee"]        = $total_fee * 100;//订单总金额
		$package_params["fee_type"]         = "1";//支付币种1(人民币),暂只支持 1;
		$package_params["notify_url"]       = $notify_url;//通知 URL
		$package_params["spbill_create_ip"] = get_client_ip();//用户浏览器端 IP
		$package_params["input_charset"]    = "UTF-8";

		$app_package = $this->create_app_package($package_params);

		$noncestr  = uniqid();
		$timestamp = time();
		//获取app signature
		$app_sign_params['appid']     = $this->appid;
		$app_sign_params['appkey']    = $this->appkey;
		$app_sign_params['noncestr']  = $noncestr;
		$app_sign_params['package']   = $app_package;
		$app_sign_params['timestamp'] = ''.$timestamp;
		$app_sign_params['traceid']   = $order_sn;
    	
		$app_signature = $this->get_signature($app_sign_params);
		unset($app_sign_params['appkey']);

		//获取prepayid
		$app_sign_params['sign_method']   = 'sha1';
		$app_sign_params['app_signature'] = $app_signature;

		$prepayid = $this->get_prepayid(json_encode($app_sign_params));

		$params['appid']     = $this->appid;
		$params['appkey']    = $this->appkey;
		$params['noncestr']  = $noncestr;
		$params['package']   = 'Sign=WXPay';
		$params['partnerid'] = $this->partner_id;
		$params['prepayid']  = $prepayid;
		$params['timestamp'] = ''.$timestamp;
		$params['sign']      = $this->get_signature($params);
		unset($params['appkey']);
		
    	return $params;
	}
	public function get_pay_unifiedorder_info($order_sn, $body, $total_fee, $notify_url){
		$noncestr = uniqid();
		$sign_params['appid']            = $this->appid;//公众账号ID
		$sign_params['mch_id']           = $this->partner_id;//商户号
		$sign_params['nonce_str']        = $noncestr;//随机字符串，不长于32位
		$sign_params['out_trade_no']     = $order_sn;//商品描述
		$sign_params['body']             = $body;//商品描述
		$sign_params['total_fee']        = $total_fee * 100;//订单总金额，只能为整数
		$sign_params['spbill_create_ip'] = get_client_ip();//终端IP
		$sign_params['notify_url']       = $notify_url;//异步回调地址
		$sign_params['trade_type']       = 'APP';//取值如下：JSAPI，NATIVE，APP，WAP
		$sign_params['sign']             = $this->get_sign($sign_params);

		//获取prepayid
		$prepayid = $this->get_unifiedorder_prepayid($sign_params);

		$params['appid']     = $this->appid;//公众账号ID
		$params['partnerid'] = $this->partner_id;//商户号
		$params['prepayid']  = $prepayid;//预支付交易会话ID
		$params['package']   = 'Sign=WXPay';//扩展字段
		$params['noncestr']  = $noncestr;//随机字符串
		$params['timestamp'] = ''.time();
		$params['sign']      = $this->get_sign($params);
		$params['appkey']    = '';

    	return $params;
	}
	public function get_unifiedorder_prepayid($sign_params){
		$data = $this->get_unifiedorder($sign_params);
		$prepay_id = $data['prepay_id'][0] ? $data['prepay_id'][0] : '';
		return $prepay_id;
	}
	//获取APP支付签名
	public function get_signature($params){
		$signPars = "";
		ksort($params);
		foreach($params as $k => $v) {
				$signPars.=$k."=".$v."&";
		}
        $signPars = rtrim($signPars, '&'); // 去除最后一个&符号
        $sign = sha1($signPars);
		return $sign;
	}
	public function get_sign($params){
		$signPars = "";
		ksort($params);
		foreach($params as $k => $v) {
				$signPars .= $k . "=" . $v . "&";
		}

        $signPars = rtrim($signPars, '&'); // 去除最后一个&符号
        $sign_temp = $signPars . '&key=' . $this->partner_key;

        $sign = md5($sign_temp);
		$sign = strtoupper($sign);

		return $sign;
	}
	public function create_app_package($parameter) {
        ksort($parameter);
        $signPars = ''; 
        foreach ($parameter as $k => $v) {
            $signPars .= strtolower($k)."=".$v."&";
        }
        $sign = strtoupper(md5($signPars.'key='.$this->partner_key));
        $signPars = '';
        foreach ($parameter as $k => $v) {
            // $signPars .= strtolower($k) . "=" . str_replace('+','%20',urlencode($v)) . "&";
            $signPars .= strtolower($k) . "=" . rawurlencode($v) . "&";
        }
        
        return $signPars . 'sign=' . $sign;
    }
	//获取请求access_token
	public function get_access_token(){
		$ch = curl_init();//初始化curl
		curl_setopt($ch, CURLOPT_URL,'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$this->appid.'&secret='.$this->app_sercert);
		curl_setopt($ch, CURLOPT_HEADER, 0);//设置header
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
		$data = curl_exec($ch);//运行curl
		curl_close($ch);
		$jsondata = json_decode($data,true);
		$access_token = $jsondata['access_token'];
		\Think\Log::write('获取请求access_token：' . print_r($jsondata, true), \Think\Log::INFO, '', $this->logs_path_file);

		return $access_token ? $access_token : '';
	}
	//生成预支付订单
	public function get_prepayid($params=''){
		$access_token = $this->get_access_token();
		$ch2 = curl_init();//初始化curl
		curl_setopt($ch2, CURLOPT_URL,'https://api.weixin.qq.com/pay/genprepay?access_token='.$access_token);
		curl_setopt($ch2, CURLOPT_HEADER, 0);//设置header
		curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
		curl_setopt($ch2, CURLOPT_POST, 1);//post提交方式
		curl_setopt($ch2, CURLOPT_POSTFIELDS, $params);
		$data = curl_exec($ch2);//运行curl
		curl_close($ch2);
		$jsondata = json_decode($data,true);
		$prepayid = $jsondata['prepayid'];
		\Think\Log::write('生成预支付订单：' . print_r($jsondata, true), \Think\Log::INFO, '', $this->logs_path_file);

		return $prepayid ? $prepayid : '';
	}
	/**
	 * 统一下单
	 * @param  array  $params [description]
	 * @return [type]         [description]
	 */
	public function get_unifiedorder($params=array()){
		$post_data = xml_encode($params);
		$ch2 = curl_init();//初始化curl
		curl_setopt($ch2, CURLOPT_URL,'https://api.mch.weixin.qq.com/pay/unifiedorder');
		curl_setopt($ch2, CURLOPT_HEADER, 0);//设置header
		curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1);//要求结果为字符串且输出到屏幕上
		curl_setopt($ch2, CURLOPT_POST, 1);//post提交方式
		curl_setopt($ch2, CURLOPT_POSTFIELDS, $post_data);
		$xml_data = curl_exec($ch2);//运行curl
		curl_close($ch2);
		$data = xml_to_array($xml_data);
		\Think\Log::write('统一下单unifiedorder：' . print_r($data, true), \Think\Log::INFO, '', $this->logs_path_file);

		return $data;
	}
	/**
	 * 验证服务器通知
	 * @param  [type] $data [description]
	 * @return [type]       [description]
	 */
	public function verify_notify($data) {
        $xml = $this->get_xml2array();
        if (! $xml || ! $data) {
            return false;
        }
        $AppSignature = $xml['appsignature'];
        unset($xml['signmethod'], $xml['appsignature']);
        $xml['appkey'] = $this->appkey;
        $sign = $this->get_signature($xml);
        if ($AppSignature != $sign) {
            return false;
        } elseif ($data['trade_state'] != 0) {
            return false;
        }
        
        return $xml;
	}
	public function new_verify_notify(){
		$data = $this->get_xml2array();
		if ($data['return_code'] != 'SUCCESS') {
            return false;
        }
        $post_sign = $data['sign'];
        unset($data['sign']);
        $check_sign = $this->get_sign($data);
        if($post_sign != $check_sign){
        	return false;
        }
        return $data;
	}
	public function get_xml2array() {
    	$xmlData = file_get_contents("php://input");
		if ($xmlData) {
			$postObj = simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA);		
            if (! is_object($postObj)) {
                return false;
            }
            $array = json_decode(json_encode($postObj), true); // xml对象转数组    
            return array_change_key_case($array, CASE_LOWER); // 所有键小写
        } else {
            return false;
        }        
    }
}
?>